﻿#include "QQChatMessageDelegate.h"

QQChatMessageDelegate::QQChatMessageDelegate(QObject* parent) : QStyledItemDelegate(parent)
{
}

QQChatMessageDelegate::~QQChatMessageDelegate()
{
}

void QQChatMessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	QQChatMessage* message = index.data(Qt::UserRole).value<QQChatMessage*>();

	QStyleOptionViewItem viewOption(option);
	this->initStyleOption(&viewOption, index);
	QRect itemRect = viewOption.rect;
	painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);

	switch (message->senderType)
	{
	case QQMessageSenderType::Self:
	{
		painter->save();
		QRect avatarRect = QRect(itemRect.width() - mIconWidth - mIconMarginLeftRight,
			itemRect.y() + mContentMargin, mIconWidth, mIconWidth);
		painter->drawPixmap(avatarRect, QPixmap(message->avatar));
		painter->restore();

		painter->save();
		painter->setPen(Qt::gray);
		QString name = message->name;
		name = viewOption.fontMetrics.elidedText(name, Qt::ElideRight,
			itemRect.width() - 4 * mIconMarginLeftRight - 2 * mIconWidth);
		int nameWidth = viewOption.fontMetrics.horizontalAdvance(name);
		int nameHeight = viewOption.fontMetrics.height();
		QRect nameRect = QRect(avatarRect.left() - nameWidth - mIconMarginLeftRight, avatarRect.top() + mNameMarginTopBottom,
			itemRect.width() - 4 * mIconMarginLeftRight - 2 * mIconWidth, nameHeight);
		painter->drawText(nameRect, Qt::AlignLeft, name);
		painter->restore();

		switch (message->type)
		{
		case QQMessageType::Text:
		case QQMessageType::Url:
		case QQMessageType::Mix:
		{
			painter->save();
			painter->setPen(Qt::NoPen);
			QTextDocument* doc = mTextDocumentCache[message->id];
			QSize docSize = doc->size().toSize();
			QRect frame = QRect(itemRect.width() - mIconWidth - 2 * mIconMarginLeftRight - docSize.width() - 2 * mContentMargin, nameRect.bottom() + mNameMarginTopBottom, docSize.width() + 2 * mContentMargin, docSize.height() + 2 * mContentMargin);
			QPainterPath path;
			path.addRoundedRect(frame, 5, 5);
			painter->fillPath(path, Qt::blue);
			painter->translate(frame.topLeft() + QPoint(mContentMargin, mContentMargin));
			doc->drawContents(painter);
			painter->restore();
			break;
		}
		case QQMessageType::Image:
		case QQMessageType::Video:
		{
			painter->save();
			QImageReader reader(message->content);
			QSize size = reader.size().scaled(mPictureMaxSize, Qt::KeepAspectRatio);
			QRect pictureRect = QRect(itemRect.width() - mIconWidth - 2 * mIconMarginLeftRight - size.width(), nameRect.bottom() + mNameMarginTopBottom, size.width(), size.height());
			painter->drawImage(pictureRect, reader.read());
			painter->restore();

			if (message->type == QQMessageType::Video)
			{
				painter->save();
				QPixmap playIcon = QPixmap(qq_settings->applicationImageLibraryDirectory("play")).scaled(48, 48);
				QRect playIconRect = QRect(pictureRect.center() - QPoint(24, 24), QSize(48, 48));
				painter->drawPixmap(playIconRect, playIcon);
				painter->restore();
			}
			break;
		}
		case QQMessageType::File:
		{
			painter->save();
			QRect fileFrame = QRect(itemRect.width() - mIconWidth - 2 * mIconMarginLeftRight - mFileFrameSize.width(), nameRect.bottom() + mNameMarginTopBottom, mFileFrameSize.width(), mFileFrameSize.height());
			QPainterPath path;
			path.addRoundedRect(fileFrame, 5, 5);
			painter->fillPath(path, Qt::white);
			painter->restore();

			QFileInfo fileInfo(message->content);

			painter->save();
			painter->setPen(Qt::black);
			QString fileName = fileInfo.fileName();
			fileName = viewOption.fontMetrics.elidedText(fileName, Qt::ElideRight, fileFrame.width() - 2 * mContentMargin);
			QRect fileNameRect = QRect(
				fileFrame.x() + 2 * mContentMargin,
				fileFrame.y() + 2 * mContentMargin,
				fileFrame.width() - mFileIconSize.width() - 2 * mContentMargin,
				fileFrame.height() - 2 * mContentMargin);
			painter->drawText(fileNameRect, Qt::AlignLeft, fileName);
			painter->restore();

			painter->save();
			painter->setPen(Qt::black);
			QString fileSize = QQSystemApi::getFileSizeString(fileInfo.size());
			QRect fileSizeRect = QRect(
				fileFrame.x() + 3 * mContentMargin,
				fileFrame.y() + fileFrame.height() - 3 * mContentMargin - viewOption.fontMetrics.height(),
				viewOption.fontMetrics.horizontalAdvance(fileSize),
				viewOption.fontMetrics.height());
			painter->drawText(fileSizeRect, Qt::AlignRight, fileSize);
			painter->restore();

			painter->save();
			QPixmap fileIcon = mFileIconProvider.icon(fileInfo).pixmap(mFileIconSize);
			fileIcon = QPixmap(message->content);
			QRect fileIconRect = QRect(
				fileFrame.x() + fileFrame.width() - mFileIconSize.width() - 2 * mContentMargin,
				fileFrame.y() + 2 * mContentMargin,
				mFileIconSize.width(),
				mFileIconSize.height());
			painter->drawPixmap(fileIconRect, fileIcon);
			painter->restore();
			break;
		}
		default:
			break;
		}
		break;
	}
	case QQMessageSenderType::Other:
	{
		painter->save();
		QPixmap icon = index.data(Qt::UserRole + 1).value<QPixmap>();
		QRect avatarRect = QRect(itemRect.x() + mIconMarginLeftRight, itemRect.y() + mContentMargin, mIconWidth, mIconWidth);
		painter->drawPixmap(avatarRect, icon);
		painter->restore();

		painter->save();
		painter->setPen(Qt::gray);
		QString name = index.data(Qt::UserRole + 2).toString();
		name = viewOption.fontMetrics.elidedText(name, Qt::ElideRight,
			itemRect.width() - 4 * mIconMarginLeftRight - 2 * mIconWidth);
		int nameHeight = viewOption.fontMetrics.height();
		QRect nameRect = QRect(avatarRect.right() + mIconMarginLeftRight, avatarRect.top() + mNameMarginTopBottom,
			itemRect.width() - 4 * mIconMarginLeftRight - 2 * mIconWidth, nameHeight);
		painter->drawText(nameRect, Qt::AlignLeft, name);
		painter->restore();

		switch (message->type)
		{
		case QQMessageType::Text:
		case QQMessageType::Url:
		case QQMessageType::Mix:
		{
			painter->save();
			painter->setPen(Qt::NoPen);
			QTextDocument* doc = mTextDocumentCache[message->id];
			QSize docSize = doc->size().toSize();
			QRect frame = QRect(itemRect.x() + mIconWidth + 2 * mIconMarginLeftRight, nameRect.bottom() + mNameMarginTopBottom, docSize.width() + 2 * mContentMargin, docSize.height() + 2 * mContentMargin);
			QPainterPath path;
			path.addRoundedRect(frame, 5, 5);
			painter->fillPath(path, Qt::white);
			painter->translate(frame.topLeft() + QPoint(mContentMargin, mContentMargin));
			doc->drawContents(painter);
			painter->restore();
			break;
		}

		case QQMessageType::Image:

		case QQMessageType::Video:
		{
			painter->save();
			QImageReader reader(message->content);
			QSize size = reader.size().scaled(mPictureMaxSize, Qt::KeepAspectRatio);
			QRect pictureRect = QRect(itemRect.x() + mIconWidth + 2 * mIconMarginLeftRight, nameRect.bottom() + mNameMarginTopBottom, size.width(), size.height());
			painter->drawImage(pictureRect, reader.read());
			painter->restore();
			if (message->type == QQMessageType::Video)
			{
				painter->save();
				QPixmap playIcon = QPixmap(qq_settings->applicationImageLibraryDirectory("play")).scaled(48, 48);
				QRect playIconRect = QRect(pictureRect.center() - QPoint(24, 24), QSize(48, 48));
				painter->drawPixmap(playIconRect, playIcon);
				painter->restore();
			}
			break;
		}

		case QQMessageType::File:
		{
			painter->save();
			QRect fileFrame = QRect(itemRect.x() + mIconWidth + 2 * mIconMarginLeftRight, nameRect.bottom() + mNameMarginTopBottom, mFileFrameSize.width(), mFileFrameSize.height());
			QPainterPath path;
			path.addRoundedRect(fileFrame, 5, 5);
			painter->fillPath(path, Qt::white);
			painter->restore();
			QFileInfo fileInfo(message->content);
			painter->save();
			painter->setPen(Qt::black);
			QString fileName = fileInfo.fileName();
			fileName = viewOption.fontMetrics.elidedText(fileName, Qt::ElideRight, fileFrame.width() - 2 * mContentMargin);
			QRect fileNameRect = QRect(
				fileFrame.x() + 2 * mContentMargin,
				fileFrame.y() + 2 * mContentMargin,
				fileFrame.width() - mFileIconSize.width() - 2 * mContentMargin,
				fileFrame.height() - 2 * mContentMargin);
			painter->drawText(fileNameRect, Qt::AlignLeft, fileName);
			painter->restore();
			painter->save();
			painter->setPen(Qt::black);
			QString fileSize = QQSystemApi::getFileSizeString(fileInfo.size());
			QRect fileSizeRect = QRect(
				fileFrame.x() + 3 * mContentMargin,
				fileFrame.y() + fileFrame.height() - 3 * mContentMargin - viewOption.fontMetrics.height(),
				viewOption.fontMetrics.horizontalAdvance(fileSize),
				viewOption.fontMetrics.height());
			painter->drawText(fileSizeRect, Qt::AlignRight, fileSize);
			painter->restore();
			painter->save();
			QPixmap fileIcon = mFileIconProvider.icon(fileInfo).pixmap(mFileIconSize);
			fileIcon = QPixmap(message->content);
			QRect fileIconRect = QRect(
				fileFrame.x() + fileFrame.width() - mFileIconSize.width() - 2 * mContentMargin,
				fileFrame.y() + 2 * mContentMargin,
				mFileIconSize.width(),
				mFileIconSize.height());
			painter->drawPixmap(fileIconRect, fileIcon);
			painter->restore();
			break;
		}

		default:
			break;
		}
		break;
	}
	default:
		break;
	}
}

QSize QQChatMessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	QQChatMessage* message = index.data(Qt::UserRole).value<QQChatMessage*>();

	QStyleOptionViewItem viewOption(option);
	this->initStyleOption(&viewOption, index);
	QRect itemRect = viewOption.rect;
	int availableWidth = itemRect.width() - 4 * mIconMarginLeftRight - 2 * mIconWidth - 2 * mContentMargin - 2 * mContentPadding;
	availableWidth = 300;

	switch (message->type)
	{
	case QQMessageType::Text:
	case QQMessageType::Url:
	case QQMessageType::Mix:
	{
		if (mTextDocumentCache[message->id] == nullptr)
		{
			QTextDocument* textDocument = new QTextDocument;
			mTextDocumentCache.insert(message->id, textDocument);
			if (message->type == QQMessageType::Url)
			{
				QFont font = viewOption.font;
				font.setUnderline(true);
				textDocument->setDefaultFont(font);
			}
			else
				textDocument->setDefaultFont(viewOption.font);
			textDocument->setPlainText(message->content);
			textDocument->setTextWidth(availableWidth);
			textDocument->setDocumentMargin(mContentPadding);
		}
		return QSize(availableWidth, mIconWidth + 2 * mContentMargin + 2 * mContentPadding + mTextDocumentCache[message->id]->size().height());
	}
	case QQMessageType::Image:
	case QQMessageType::Video:
	{
		QImageReader reader(message->content);
		QSize size = reader.size().scaled(availableWidth, mPictureMaxSize.height(), Qt::KeepAspectRatio);
		return QSize(availableWidth, mIconWidth + 2 * mContentMargin + 2 * mContentPadding + size.height());
	}
	case QQMessageType::File:
	{
		return QSize(availableWidth, mIconWidth + 2 * mContentMargin + 2 * mContentPadding + mFileFrameSize.height());
	}
	case QQMessageType::Voice:
	{
		return QSize(availableWidth, mIconWidth + 2 * mContentMargin + 2 * mContentPadding);
	}
	default:
		break;
	}
	return QStyledItemDelegate::sizeHint(option, index);
}
